/* @flow */

import config from '../config'
import {ASSET_TYPES} from 'shared/constants'
import {warn, isPlainObject} from '../util/index'

export function initAssetRegisters(Vue: GlobalAPI) {
  /**
   * Create asset registration methods.
   */
  //ASSERT_TYPES包括component、directive、filter
  ASSET_TYPES.forEach(type => {
    //在Vue构造函数上定义静态方法component、directive、filter，
    //分别用于获取或者设置全局的组件、指令与过滤器
    Vue[type] = function (id: string,
                          definition: Function | Object): Function | Object | void {
      //如果未提供definition，则是获取相应的组件、指令或者过滤器
      if (!definition) {
        return this.options[type + 's'][id]
      } else {
        /* istanbul ignore if */
        if (process.env.NODE_ENV !== 'production') {
          if (type === 'component' && config.isReservedTag(id)) {
            warn(
              'Do not use built-in or reserved HTML elements as component ' +
              'id: ' + id
            )
          }
        }

        // 对于component方法，如果definition不是对象而是函数的话，则说明是通过Vue.extend方法创建的Vue子构造函数或者是异步组件
        if (type === 'component' && isPlainObject(definition)) {
          definition.name = definition.name || id
          //_base指向Vue构造函数，因为这里的this可能指向Vue构造函数及其子构造函数，
          //而_base总是指向Vue构造函数。
          //也就是说，即使使用Vue的子构造函数添加全局组件，该全局组件的选项也是在Vue构造函数
          //的基础上进行扩展的，而不是子构造函数。
          //另外，每个组件实际上都被转换成Vue构造函数的子构造函数
          definition = this.options._base.extend(definition)
        }
        if (type === 'directive' && typeof definition === 'function') {
          definition = {bind: definition, update: definition}
        }

        //对于component组件来说，注册全局组件时，总是在Vue构造函数的基础上进行扩展，如上所示。
        //但是总是将扩展后得到的组件存放到当前构造函数中，所以通过子构造函数注册的全局组件，必须通过
        //该子构造函数创建的Vue实例才能找到注册的组件
        this.options[type + 's'][id] = definition
        return definition
      }
    }
  })
}
